use std::time::{SystemTime, UNIX_EPOCH};

use anyhow::Result;
use base64::Engine;
use base64::engine::general_purpose;
use hmac::{Hmac, Mac};
use reqwest::Client;
use serde::Serialize;
use sha2::Sha256;
use urlencoding::encode;

type HmacSha256 = Hmac<Sha256>;

#[derive(Serialize)]
struct DingTalkText<'a> {
    msgtype: &'a str,
    text: DingTalkContent<'a>,
}

#[derive(Serialize)]
struct DingTalkContent<'a> {
    content: &'a str,
}
// ---------------------------- 发送钉钉消息函数 ----------------------------

/// 异步函数：发送钉钉文本消息
///
/// # 参数
/// - `error_content`: 消息内容（错误信息）
///
/// # 返回值
/// - `Result<()>`：操作成功返回 Ok，失败返回 Err
pub async fn send_msg_to_ding(error_content: &str) -> Result<()> {
    let client = Client::new();
    const UNSAFE_URL: &str = "https://oapi.dingtalk.com/robot/send?access_token=62b66eb247450f3413673444385b3901dd0f9659940fcb02d5dac6de3f0dea76";
    const SECRET: &str = "SEC1aa8031bdfbc8bb4e1f5b8ff48c99efd42be0e073ea28b71ab419a24489da8f1";

    // 毫秒级时间戳
    let timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis();

    // 构造签名字符串
    let string_to_sign = format!("{}\n{}", timestamp, SECRET);

    // HMAC-SHA256 签名
    let mut mac = HmacSha256::new_from_slice(SECRET.as_bytes())?;
    mac.update(string_to_sign.as_bytes());
    let result = mac.finalize().into_bytes();
    let encoded = general_purpose::STANDARD.encode(result);
    let sign = encode(&encoded);

    let url = format!("{UNSAFE_URL}&timestamp={timestamp}&sign={sign}");

    let obj = DingTalkText {
        msgtype: "text",
        text: DingTalkContent {
            content: error_content,
        },
    };

    client.post(&url).json(&obj).send().await?.text().await?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_send_dingding() {
        let error_content = "测试错误信息";
        let result = send_msg_to_ding(error_content).await;

        match result {
            Ok(_) => println!("发送成功"),
            Err(e) => eprintln!("发送失败: {:?}", e),
        }
    }
}
